grammar JKlasy;

options {
	language = Java;
  	k = *;
}

tokens {
	GREQ 		= '>=';
	LEQ 		= '<=';
	ARROW 		= '=>';
	ASSIGN 		= ':=';
	NOTEQ   	= '!=';
	PLUS 		= '+' ;
	MINUS		= '-' ;
	MULT		= '*' ;
	LPAREN  	= '(' ;
	RPAREN  	= ')' ;
	LCURLY  	= '{' ;
	RCURLY  	= '}' ;
	LSQUARE 	= '[' ;
	RSQUARE 	= ']' ;
	SEMI    	= ';' ;
	COMA		= ',';
	DOT			= '.';
	PROGRAM 	= 'program';
	CLASS		= 'class';
	IMPLEMENTATION 	= 'implementation';
	BEGIN 		= 'begin';
	END			= 'end';
	IF 			= 'if';
	THEN 		= 'then';
	ELSE		= 'else';
	WHILE		= 'while';
	LOOP 		= 'loop';
	RETURN		= 'return';
	INTT		= 'integer';
	BOOLT		= 'boolean';
	CHART		= 'char';
	STRINGT		= 'string';
	REALT		= 'real';
	OPERATION 	= 'operation';
	IS			= 'is';
	INPUT		= 'input';
	OUTPUT		= 'output';
	DIV			= 'div';
	MOD			= 'mod';
	NOT			= 'not';
	AND			= 'and';
	OR			= 'or';
	TRUE		= 'true';
	FALSE		= 'false';	
	ARRAY 		= 'array';
	OF			= 'of';
	NULL		= 'null';
	
	ARRAY;
	MAINPART;
	CLASSDEFINITION;
	VARIABLEDECLARATION;
	DECLARATIONTYPE;
	PARAMETERTYPE;
	OPERATIONDESCRIPTOR;
	OPERATIONALGORITHM;
	ARGUMENTS;
	VARIABLES;
	STATEMENTS;
	IFSTATEMENT;
	CALLSTATEMENT;
	CALL;
	SIMPLECALL;
	ASSIGNSTATEMENT;
	WHILESTATEMENT;
	INPUTSTATEMENT;
	OUTPUTSTATEMENT;
	EXPRESSION;
	RESULT;
	INDEX;
	CAST;
}

@parser::header {
package compiler.parser;
}

@lexer::header {
package compiler.lexer;
}


/*------------------------------------------------------------------
 * PARSER RULES
 *------------------------------------------------------------------*/

program:
	main_part 
	(class_definition)* 
	;

main_part:
	PROGRAM
		(variable_declaration)* 
	BEGIN
	  statements 
	END SEMI 
	;
	
class_definition:    
	  ID COLON CLASS 
		  (operation_descriptor SEMI)* 
	  IMPLEMENTATION
	  	(variable_declaration)*
	  	(operation_algorithm)*
	  END SEMI 
	;
	
variable_declaration:    
    ID (COMA ID)* COLON declaration_type SEMI
	;

declaration_type: 
	(ARRAY LSQUARE NUMBER RSQUARE OF)? simple_type
	;

parameter_type:
	(ARRAY LSQUARE RSQUARE OF)? simple_type
	;
	
simple_type:
      INTT
	| BOOLT
	| STRINGT
	| REALT
	| CHART
	| ID
	;

operation_descriptor:    	
    designator COLON 
    		LPAREN 
    			(parameter_type (COMA parameter_type)* )? 
    		RPAREN
    	(ARROW parameter_type)?
	;
	
designator:
	  ID
	| operator
	;

operation_algorithm:
    OPERATION COLON designator
    	LPAREN 
    		(ID (COMA ID)* )? 
    	RPAREN IS
		  (variable_declaration)*
	  BEGIN
	  	statements
	  	(RETURN expression SEMI)?
	  END SEMI
	;

statements:   
   (statement)*
	;

statement:
      assign_statement SEMI
	| if_statement 
	| while_statement SEMI
	| input_statement SEMI
	| output_statement SEMI
	| call_statement SEMI
	;

if_statement:
	  IF LPAREN expression RPAREN 
		 conditional_option 
	  	(ELSE conditional_option)?
	;
	
conditional_option:
	  statement 
	| BEGIN statements END SEMI
	;
	
assign_statement:
	  ID ASSIGN expression	  	
	;
	
call_statement:
	  call
	;

call:	
	  (ID DOT)* simple_call
	;
	
simple_call:	  
	  ID LPAREN (expression (COMA expression)*)? RPAREN
	;
	
while_statement:	  
	  WHILE LPAREN expression RPAREN LOOP
			statements
	  END LOOP
	  ;
	  
input_statement:	 	
	  INPUT ID (COMA ID)*
		;
			
output_statement:	  
	  OUTPUT ID (COMA ID)*
	;
	
expression:
	  boolean_expression
	;

boolean_expression:
	  relational_expression (boolean_operator relational_expression)*
	;
	
relational_expression:
	  a1_expression (relational_operator a1_expression)?
	;

a1_expression:
	  a2_expression (additive_operator a2_expression)*
	;

a2_expression:
	  a3_expression (multiplicative_operator a3_expression)*
	;

a3_expression:
	  NUMBER
	| TRUE
	| FALSE
	| STRING
	| CHAR
	| NULL
	| ID (LSQUARE expression RSQUARE)?
	| cast
	| call
	| NOT a3_expression
	;
	
cast:		
	(LSQUARE simple_type RSQUARE)? LPAREN expression RPAREN
	;

boolean_operator:
	  AND
	| OR
	;
	
relational_operator:
	  EQUAL
	| NOTEQ
  	| GR 
  	| GREQ
  	| LS 
  	| LEQ
	;

additive_operator:
	  PLUS
	| MINUS
	;

multiplicative_operator:
	  DIV 
	| MOD
	| MULT
	;

operator:
	  relational_operator
	| additive_operator
	| multiplicative_operator
	| boolean_operator
	| NOT
	;	
	
/*------------------------------------------------------------------
 * LEXER RULES
 *------------------------------------------------------------------*/

NUMBER	: ('1' .. '9') ('0' .. '9')* | '0';

REALNUMBER : NUMBER '.' ('0' .. '9')+;

ID 	: ('a' .. 'z' | 'A' .. 'Z') ( 'a' .. 'z' | 'A' .. 'Z' | '0' .. '9')* ;

STRING 	:  '"' (~ '"')* '"';

WHITESPACE : ( '\t' | ' ' | '\r' | '\n' )+ { $channel = HIDDEN; } ;

COMMENT : '/*' ( options {greedy=false;} : . )* '*/' { $channel = HIDDEN; } ;

CHAR 	: '\'' ('a' .. 'z' | 'A' .. 'Z') '\'';

COLON 	: ':' ('=' {$type = ASSIGN;})?;

EQUAL 	: '=' ('>' {$type = ARROW;})?;

GR 	: '>' ('=' {$type= GREQ;})?;

LS 	: '<' ('=' {$type = LEQ;})?;
